package com.shuang.graph21;

import java.util.*;
 
 
    //定义一个类用来存放位置坐标xy 还有用到的g h f参数
//g 代表从起点到该节点的距离
//h 代表从该节点到终点的距离
//f 代表从起点到终点的距离 即为g+h
class knight{
    int x;
    int y;
 
    int g;
    int h;
    int f;
 
    public knight(){
    }
 
    public  knight(int x, int y, int g, int h, int f){
        this.x = x;
        this.y = y;
        this.g =  g;
        this.h = h;
        this.f = f;
    }
}
 
 
//自定义优先级队列中的排序方式 根据f的值从小到大排序
class MyComparison implements Comparator<knight> {
    @Override
    public int compare(knight f1, knight f2) {
        return Integer.compare(f1.f, f2.f);
    }
}
 
 
//A*算法 启发式函数 采用 欧拉距离计算方式）
public class Main{
 
    //计算h 从该节点位置到终点的距离
    public static int Heuristic(int x, int y) { // 欧拉距离
    return (x - b1) * (x - b1) + (y - b2) * (y - b2); // 统一不开根号，这样可以提高精度
    }
 
 
    //定义全局变量 
    //第一是用于标记访问过的位置不在访问，第二是存放从起点到终点（该位置）的最短步数
    static int[][] moves = new int[1001][1001];
 
    //可以移动的八个方向
    static int[][] dir=new int[][]{{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};
 
    //终点位置坐标
    static int b1, b2;
 
    //定义优先级队列 按照f从小到大的规则排列
    static PriorityQueue<knight> que = new PriorityQueue<>(new MyComparison());
 
    //a*算法实现(优化的深搜, 优先级队列 按照f最小的规则排列 这样的深搜就能按着靠近终点的方向在深搜 而不是随意的方向一直深搜）
    public static void aStar(knight k){
        //k是传进来的起点的各个参数 先加入队列中
        que.add(k);
 
        //用于记录当前从队列中取到的节点 和 当前节点的下一个方向的节点
        knight cur;
 
        //开始深搜
        while(!que.isEmpty()){
            //取出当前节点
            cur = que.poll();
 
            //如果到达终点了直接结束即可
            if(cur.x == b1 && cur.y == b2){
                break;
            }
 
            //寻找当前节点的八个方向
            for (int i = 0; i < 8; i++){
                int nextX = cur.x + dir[i][0];
                int nextY = cur.y + dir[i][1];
 
                // 越界判断
                if (nextX < 1 || nextX > 1000 || nextY < 1 || nextY > 1000) {
                    continue;
                }
 
                // 起点是(a1,a2)，它的moves值是0。如果一个格子moves值为0且它不是起点，则它未被访问。
                // 如果它就是起点，这个判断可以防止算法回到起点。
                boolean isStartPoint = (nextX == k.x && nextY == k.y);
 
                // 如果位置没被访问过
                if (moves[nextX][nextY] == 0 && !isStartPoint) {
                    moves[nextX][nextY] = moves[cur.x][cur.y] + 1;
 
                    // 必须在循环内部为每个邻居创建一个新的对象
                    // 否则，队列中所有的元素都将引用同一个对象，导致逻辑错误
                    knight nextNode = new knight();
                    nextNode.x = nextX;
                    nextNode.y = nextY;
 
                    // 开始计算F
                    nextNode.g = cur.g + 5; // 统一不开根号，这样可以提高精度，马走日，根号下(1^2 + 2^2) -> 平方是 5
                    nextNode.h = Heuristic(nextNode.x, nextNode.y);
                    nextNode.f = nextNode.g + nextNode.h;
                     
                    que.add(nextNode);
                }
            }
        }
    }
 
    public static void main(String[] args){
        int n, a1, a2;
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
 
        while(n-- > 0){
            a1 = sc.nextInt();
            a2 = sc.nextInt();
             
            b1 = sc.nextInt();
            b2 = sc.nextInt();
 
             // 清空队列
            que.clear(); 
            // 重置moves数组
            for (int[] row : moves) {
                Arrays.fill(row, 0);
            }
 
            int g = 0;
            int h = Heuristic(a1, a2);
            int f = g + h;
 
            knight start = new knight(a1, a2, g, h, f);
 
            aStar(start);
 
            while(!que.isEmpty()){
                que.poll(); // 队列清空
            } 
 
            System.out.println(moves[b1][b2]);
        }
    }
}